#include "stdafx.h"
#include "MaterialCoder.h"
#include <sstream>

MaterialCoderLineArea::MaterialCoderLineArea(MaterialTextEdit *editor) 
	: QWidget(editor) 
{
	mEditor = editor;
	
}
MaterialCoderLineArea::~MaterialCoderLineArea()
{}

QSize MaterialCoderLineArea::sizeHint() const {
	return QSize(mEditor->lineNumberAreaWidth(), 0);
}

void MaterialCoderLineArea::paintEvent(QPaintEvent *event) {
	mEditor->lineNumberAreaPaintEvent(event);
}
 MaterialCodeHighlighter::MaterialCodeHighlighter(QTextDocument *parent)
     : QSyntaxHighlighter(parent)
 {
	 numberFormat.setUnderlineStyle( QTextCharFormat::SingleUnderline );
	 numberFormat.setForeground(Qt::blue);
	 numberFormat.setFontItalic( true );
	classFormat.setForeground(Qt::darkRed);
	classFormat.setFontWeight(QFont::Bold);
	quotationFormat.setForeground(Qt::red);	 
	functionFormat.setForeground(Qt::blue); functionFormat.setFontItalic(true);  
	singleLineCommentFormat.setForeground(QColor( 123, 123, 123, 255 ));	 
	multiLineCommentFormat.setForeground(Qt::darkGreen);

	commentStartExpression = QRegExp("/\\*");
	commentEndExpression = QRegExp("\\*/");
	
	
	Rules.append(Rule(QRegExp("\\b[0-9]+\.[0-9]+\\b"),numberFormat));
	Rules.append(Rule(QRegExp("\\b[0-9]+\\b"),numberFormat));
	Rules.append(Rule(QRegExp("\\bQ[A-Za-z]+\\b"),classFormat));
	Rules.append(Rule(QRegExp("\".*\""),quotationFormat));
	Rules.append(Rule(QRegExp("\\b[A-Za-z0-9_]+(?=\\()"),functionFormat));
	Rules.append(Rule(QRegExp("//[^\n]*"),singleLineCommentFormat));
	
	QTextCharFormat fmt0;
	fmt0.setForeground(QColor(Qt::darkBlue)); 
		fmt0.setFontWeight( QFont::Bold );
		fmt0.setFontItalic( false );
	QTextCharFormat fmt1;
	fmt1.setForeground(QColor(Qt::darkYellow)); 
		fmt1.setFontWeight( QFont::Bold );
		fmt1.setFontItalic( true );
	QTextCharFormat fmt2;
	fmt2.setForeground(QColor(Qt::blue)); 
		fmt2.setFontWeight( QFont::Bold );
		fmt2.setFontItalic( false );
	QTextCharFormat fmt3;
	fmt3.setForeground(QColor(Qt::darkBlue)); 
		fmt3.setFontWeight( QFont::Normal );
		fmt3.setFontItalic( true );

	std::string wordlist0("vertex_program geometry_program fragment_program default_params material technique pass texture_unit vertex_program_ref geometry_program_ref fragment_program_ref shadow_caster_vertex_program_ref shadow_receiver_fragment_program_ref shadow_receiver_vertex_program_ref abstract import from cg hlsl glsl ");
	std::string wordlist1("source syntax manual_named_constants entry_point profiles includes_skeletal_animation includes_morph_animation includes_pose_animation uses_vertex_texture_fetch uses_adjacency_information target preprocessor_defines column_major_matrices attach input_operation_type output_operation_type max_output_vertices delegate param_indexed param_indexed_auto param_named param_named_auto lod_distances receive_shadows transparency_casts_shadows set set_texture_alias scheme lod_index shadow_caster_material shadow_receiver_material gpu_vendor_rule gpu_device_rule ambient diffuse specular emissive scene_blend separate_scene_blend depth_check depth_write depth_func depth_bias iteration_depth_bias alpha_rejection alpha_to_coverage light_scissor light_clip_planes illumination_stage transparent_sorting normalise_normals cull_hardware cull_software lighting shading polygon_mode polygon_mode_overrideable fog_override colour_write max_lights start_light iteration point_size point_sprites point_size_attenuation point_size_min point_size_max texture_alias texture anim_texture cubic_texture tex_coord_set tex_address_mode tex_border_colour filtering max_anisotropy mipmap_bias colour_op colour_op_ex colour_op_multipass_fallback alpha_op_ex env_map scroll scroll_anim rotate rotate_anim scale wave_xform transform binding_type content_type ");
	std::string wordlist2("int half float float2 float3 float4 float3x3 float3x4 float4x3 float4x4 double include exclude true false on off none vertexcolour add modulate alpha_blend colour_blend one zero dest_colour src_colour one_minus_dest_colour one_minus_src_colour dest_alpha src_alpha one_minus_dest_alpha one_minus_src_alpha always_fail always_pass less less_equal equal not_equal greater_equal greater clockwise anticlockwise back front flat gouraud phong solid wireframe points type linear exp exp2 colour density start end once once_per_light per_light per_n_lights point directional spot 1d 2d 3d cubic PF_L8 PF_L16 PF_A8 PF_A4L4 PF_BYTE_LA PF_R5G6B5 PF_B5G6R5 PF_R3G3B2 PF_A4R4G4B4 PF_A1R5G5B5 PF_R8G8B8 PF_B8G8R8 PF_A8R8G8B8 PF_A8B8G8R8 PF_B8G8R8A8 PF_R8G8B8A8 PF_X8R8G8B8 PF_X8B8G8R8 PF_A2R10G10B10 PF_A2B10G10R10 PF_FLOAT16_R PF_FLOAT16_RGB PF_FLOAT16_RGBA PF_FLOAT32_R PF_FLOAT32_RGB PF_FLOAT32_RGBA PF_SHORT_RGBA combinedUVW separateUV vertex fragment named shadow wrap clamp mirror border bilinear trilinear anisotropic replace source1 source2 modulate_x2 modulate_x4 add_signed add_smooth subtract blend_diffuse_alpha blend_texture_alpha blend_current_alpha blend_manual dotproduct blend_diffuse_colour src_current src_texture src_diffuse src_specular src_manual spherical planar cubic_reflection cubic_normal xform_type scroll_x scroll_y scale_x scale_y wave_type sine triangle square sawtooth inverse_sawtooth base frequency phase amplitude arbfp1 arbvp1 glslv glslf gp4vp gp4gp gp4fp fp20 fp30 fp40 vp20 vp30 vp40 ps_1_1 ps_1_2 ps_1_3 ps_1_4 ps_2_0 ps_2_a ps_2_b ps_2_x ps_3_0 ps_3_x vs_1_1 vs_2_0 vs_2_a vs_2_x vs_3_0 1d 2d 3d 4d ");
	std::string wordlist3("world_matrix inverse_world_matrix transpose_world_matrix inverse_transpose_world_matrix world_matrix_array_3x4 view_matrix inverse_view_matrix transpose_view_matrix inverse_transpose_view_matrix projection_matrix inverse_projection_matrix transpose_projection_matrix inverse_transpose_projection_matrix worldview_matrix inverse_worldview_matrix transpose_worldview_matrix inverse_transpose_worldview_matrix viewproj_matrix inverse_viewproj_matrix transpose_viewproj_matrix inverse_transpose_viewproj_matrix worldviewproj_matrix inverse_worldviewproj_matrix transpose_worldviewproj_matrix inverse_transpose_worldviewproj_matrix texture_matrix render_target_flipping light_diffuse_colour light_specular_colour light_attenuation spotlight_params light_position light_direction light_position_object_space light_direction_object_space light_distance_object_space light_position_view_space light_direction_view_space light_power light_diffuse_colour_power_scaled light_specular_colour_power_scaled light_number light_diffuse_colour_array light_specular_colour_array light_diffuse_colour_power_scaled_array light_specular_colour_power_scaled_array light_attenuation_array spotlight_params_array light_position_array light_direction_array light_position_object_space_array light_direction_object_space_array light_distance_object_space_array light_position_view_space_array light_direction_view_space_array light_power_array light_count light_casts_shadows ambient_light_colour surface_ambient_colour surface_diffuse_colour surface_specular_colour surface_emissive_colour surface_shininess derived_ambient_light_colour derived_scene_colour derived_light_diffuse_colour derived_light_specular_colour derived_light_diffuse_colour_array derived_light_specular_colour_array fog_colour fog_params camera_position camera_position_object_space lod_camera_position lod_camera_position_object_space time_0_x costime_0_x sintime_0_x tantime_0_x time_0_x_packed time_0_1 costime_0_1 sintime_0_1 tantime_0_1 time_0_1_packed time_0_2pi costime_0_2pi sintime_0_2pi tantime_0_2pi time_0_2pi_packed frame_time fps viewport_width viewport_height inverse_viewport_width inverse_viewport_height viewport_size texel_offsets view_direction view_side_vector view_up_vector fov near_clip_distance far_clip_distance texture_viewproj_matrix texture_viewproj_matrix_array texture_worldviewproj_matrix texture_worldviewproj_matrix_array spotlight_viewproj_matrix spotlight_worldviewproj_matrix scene_depth_range shadow_scene_depth_range shadow_colour shadow_extrusion_distance texture_size inverse_texture_size packed_texture_size pass_number pass_iteration_number animation_parametric custom ");
	
	std::stringstream ss(wordlist0);
	std::string str;
	while( ss >> str ) { Ogre::StringUtil::trim( str ); if( !str.empty() ) LangRules.append( Rule( QRegExp( "\\b"+QString(str.c_str())+"\\b" ), fmt0 ) ); }
	ss.str(wordlist1);
	while( ss >> str ) { Ogre::StringUtil::trim( str ); if( !str.empty() ) LangRules.append( Rule( QRegExp( "\\b"+QString(str.c_str())+"\\b" ), fmt1 ) ); }
	ss.str(wordlist2);
	while( ss >> str ) { Ogre::StringUtil::trim( str ); if( !str.empty() ) LangRules.append( Rule( QRegExp( "\\b"+QString(str.c_str())+"\\b" ), fmt2 ) ); }
	ss.str(wordlist3);
	while( ss >> str ) { Ogre::StringUtil::trim( str ); if( !str.empty() ) LangRules.append( Rule( QRegExp( "\\b"+QString(str.c_str())+"\\b" ), fmt3 ) ); }
 }

void MaterialCodeHighlighter::highlightBlock(const QString &text)
{
	foreach (const Rule &rule, Rules) {
		QRegExp expression(rule.pattern);
		int index = expression.indexIn(text);
		while (index >= 0) {
			int length = expression.matchedLength();
			setFormat(index, length, rule.format);
			index = expression.indexIn(text, index + length);
		}
	}

	foreach (const Rule &rule, LangRules) {
		QRegExp expression(rule.pattern);
		int index = expression.indexIn(text);
		while (index >= 0) {
			int length = expression.matchedLength();
			setFormat(index, length, rule.format);
			index = expression.indexIn(text, index + length);
		}
	}
	setCurrentBlockState(0);
	int startIndex = 0;
	if (previousBlockState() != 1)
		startIndex = commentStartExpression.indexIn(text);
	while (startIndex >= 0) {
		int endIndex = commentEndExpression.indexIn(text, startIndex);
		int commentLength;
		if (endIndex == -1) {
			setCurrentBlockState(1);
			commentLength = text.length() - startIndex;
		} 
		else {
			commentLength = endIndex - startIndex
							+ commentEndExpression.matchedLength();
		}
		setFormat(startIndex, commentLength, multiLineCommentFormat);
		startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
	}
}
MaterialCompleter::MaterialCompleter( MaterialTextEdit * parent ) : QMenu( parent )
{
	mEdit = parent;
	mLay = new QVBoxLayout( this );
	setLayout(mLay); 
	mList = new QListWidget( this );
	mLay->addWidget( mList );
	mList->setFocus();

	mLay->setContentsMargins( 0,0,0,0 );
	setContentsMargins( 0,0,0,0 );
	mList->setContentsMargins( 0,0,0,0 );

	setContextMenuPolicy( Qt::CustomContextMenu );
	connect( mList, SIGNAL(itemDoubleClicked( QListWidgetItem * )), this, SLOT(insertCompletion( QListWidgetItem* )) );
	std::string wordlist("vertex_program geometry_program fragment_program default_params material technique pass texture_unit vertex_program_ref geometry_program_ref fragment_program_ref shadow_caster_vertex_program_ref shadow_receiver_fragment_program_ref shadow_receiver_vertex_program_ref abstract import from cg hlsl glsl ");
	wordlist+="source syntax manual_named_constants entry_point profiles includes_skeletal_animation includes_morph_animation includes_pose_animation uses_vertex_texture_fetch uses_adjacency_information target preprocessor_defines column_major_matrices attach input_operation_type output_operation_type max_output_vertices delegate param_indexed param_indexed_auto param_named param_named_auto lod_distances receive_shadows transparency_casts_shadows set set_texture_alias scheme lod_index shadow_caster_material shadow_receiver_material gpu_vendor_rule gpu_device_rule ambient diffuse specular emissive scene_blend separate_scene_blend depth_check depth_write depth_func depth_bias iteration_depth_bias alpha_rejection alpha_to_coverage light_scissor light_clip_planes illumination_stage transparent_sorting normalise_normals cull_hardware cull_software lighting shading polygon_mode polygon_mode_overrideable fog_override colour_write max_lights start_light iteration point_size point_sprites point_size_attenuation point_size_min point_size_max texture_alias texture anim_texture cubic_texture tex_coord_set tex_address_mode tex_border_colour filtering max_anisotropy mipmap_bias colour_op colour_op_ex colour_op_multipass_fallback alpha_op_ex env_map scroll scroll_anim rotate rotate_anim scale wave_xform transform binding_type content_type ";
	wordlist+="int half float float2 float3 float4 float3x3 float3x4 float4x3 float4x4 double include exclude true false on off none vertexcolour add modulate alpha_blend colour_blend one zero dest_colour src_colour one_minus_dest_colour one_minus_src_colour dest_alpha src_alpha one_minus_dest_alpha one_minus_src_alpha always_fail always_pass less less_equal equal not_equal greater_equal greater clockwise anticlockwise back front flat gouraud phong solid wireframe points type linear exp exp2 colour density start end once once_per_light per_light per_n_lights point directional spot 1d 2d 3d cubic PF_L8 PF_L16 PF_A8 PF_A4L4 PF_BYTE_LA PF_R5G6B5 PF_B5G6R5 PF_R3G3B2 PF_A4R4G4B4 PF_A1R5G5B5 PF_R8G8B8 PF_B8G8R8 PF_A8R8G8B8 PF_A8B8G8R8 PF_B8G8R8A8 PF_R8G8B8A8 PF_X8R8G8B8 PF_X8B8G8R8 PF_A2R10G10B10 PF_A2B10G10R10 PF_FLOAT16_R PF_FLOAT16_RGB PF_FLOAT16_RGBA PF_FLOAT32_R PF_FLOAT32_RGB PF_FLOAT32_RGBA PF_SHORT_RGBA combinedUVW separateUV vertex fragment named shadow wrap clamp mirror border bilinear trilinear anisotropic replace source1 source2 modulate_x2 modulate_x4 add_signed add_smooth subtract blend_diffuse_alpha blend_texture_alpha blend_current_alpha blend_manual dotproduct blend_diffuse_colour src_current src_texture src_diffuse src_specular src_manual spherical planar cubic_reflection cubic_normal xform_type scroll_x scroll_y scale_x scale_y wave_type sine triangle square sawtooth inverse_sawtooth base frequency phase amplitude arbfp1 arbvp1 glslv glslf gp4vp gp4gp gp4fp fp20 fp30 fp40 vp20 vp30 vp40 ps_1_1 ps_1_2 ps_1_3 ps_1_4 ps_2_0 ps_2_a ps_2_b ps_2_x ps_3_0 ps_3_x vs_1_1 vs_2_0 vs_2_a vs_2_x vs_3_0 1d 2d 3d 4d ";
	wordlist+="world_matrix inverse_world_matrix transpose_world_matrix inverse_transpose_world_matrix world_matrix_array_3x4 view_matrix inverse_view_matrix transpose_view_matrix inverse_transpose_view_matrix projection_matrix inverse_projection_matrix transpose_projection_matrix inverse_transpose_projection_matrix worldview_matrix inverse_worldview_matrix transpose_worldview_matrix inverse_transpose_worldview_matrix viewproj_matrix inverse_viewproj_matrix transpose_viewproj_matrix inverse_transpose_viewproj_matrix worldviewproj_matrix inverse_worldviewproj_matrix transpose_worldviewproj_matrix inverse_transpose_worldviewproj_matrix texture_matrix render_target_flipping light_diffuse_colour light_specular_colour light_attenuation spotlight_params light_position light_direction light_position_object_space light_direction_object_space light_distance_object_space light_position_view_space light_direction_view_space light_power light_diffuse_colour_power_scaled light_specular_colour_power_scaled light_number light_diffuse_colour_array light_specular_colour_array light_diffuse_colour_power_scaled_array light_specular_colour_power_scaled_array light_attenuation_array spotlight_params_array light_position_array light_direction_array light_position_object_space_array light_direction_object_space_array light_distance_object_space_array light_position_view_space_array light_direction_view_space_array light_power_array light_count light_casts_shadows ambient_light_colour surface_ambient_colour surface_diffuse_colour surface_specular_colour surface_emissive_colour surface_shininess derived_ambient_light_colour derived_scene_colour derived_light_diffuse_colour derived_light_specular_colour derived_light_diffuse_colour_array derived_light_specular_colour_array fog_colour fog_params camera_position camera_position_object_space lod_camera_position lod_camera_position_object_space time_0_x costime_0_x sintime_0_x tantime_0_x time_0_x_packed time_0_1 costime_0_1 sintime_0_1 tantime_0_1 time_0_1_packed time_0_2pi costime_0_2pi sintime_0_2pi tantime_0_2pi time_0_2pi_packed frame_time fps viewport_width viewport_height inverse_viewport_width inverse_viewport_height viewport_size texel_offsets view_direction view_side_vector view_up_vector fov near_clip_distance far_clip_distance texture_viewproj_matrix texture_viewproj_matrix_array texture_worldviewproj_matrix texture_worldviewproj_matrix_array spotlight_viewproj_matrix spotlight_worldviewproj_matrix scene_depth_range shadow_scene_depth_range shadow_colour shadow_extrusion_distance texture_size inverse_texture_size packed_texture_size pass_number pass_iteration_number animation_parametric custom ";
	std::stringstream ss( wordlist );
	std::string str;
	while( ss >> str )
	{
		if( !str.empty() )
		mWords << str.c_str();
	}

}
MaterialCompleter::~MaterialCompleter(){}
	
void MaterialCompleter::popup( const QPoint &pos )
{
	setFixedSize( 200, 100 );
	show();
	mList->clear();
	mCursor = mEdit->textCursor();
	mCursor.movePosition( QTextCursor::StartOfWord, QTextCursor::KeepAnchor );
	QString sel = mCursor.selectedText();
	for( auto i=mWords.begin(); i!=mWords.end(); i++ )
	{
		QString word = *i;
		if( word.startsWith( sel ) ) mList->addItem( *i );
	}
	QMenu::popup( pos );
	if( mList->count() == 0 )
		hide();
}
void MaterialCompleter::insertCompletion( QListWidgetItem* itm )
{ 
	QString completionPrefix = mEdit->textUnderCursor();
	QString completion = itm->text();
	int extra = completion.length() - completionPrefix.length();
	QTextCursor tc( mEdit->textCursor() );
	/*tc.movePosition(QTextCursor::Left,QTextCursor::MoveAnchor);
    tc.movePosition(QTextCursor::EndOfWord,QTextCursor::KeepAnchor);*/
	tc.movePosition(QTextCursor::Left);
    tc.movePosition(QTextCursor::EndOfWord);
    tc.insertText(completion.right(extra));
    mEdit->setTextCursor(tc);
	hide();

}

MaterialTextEdit::MaterialTextEdit( QTabWidget * parent ) : QPlainTextEdit( parent )
{
	mLineArea = new MaterialCoderLineArea(this);
	setWordWrapMode( QTextOption::NoWrap );
	connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
	connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int)));
	connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
	
	setupEditor( );
	updateLineNumberAreaWidth(0);
	highlightCurrentLine();
	setTabStopWidth( 30 );
}
MaterialTextEdit::~MaterialTextEdit( ){}

int MaterialTextEdit::lineNumberAreaWidth()
{
	int digits = 1;
	int max = qMax(1, document()->blockCount());
	while (max >= 10) {
		max /= 10;
		++digits;
	}

	int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits;

	return space;
}

void MaterialTextEdit::updateLineNumberAreaWidth(int /* newBlockCount */)
{
	setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}
QString MaterialTextEdit::textUnderCursor() const
{
    QTextCursor tc = textCursor();
    tc.select(QTextCursor::WordUnderCursor);
    return tc.selectedText();
}
void MaterialTextEdit::updateLineNumberArea(const QRect &rect, int dy)
{
    if (dy)
        mLineArea->scroll(0, dy);
    else
        mLineArea->update(0, rect.y(), mLineArea->width(), rect.height());

    if (rect.contains(viewport()->rect()))
        updateLineNumberAreaWidth(0);
}
QString MaterialTextEdit::currentLine( int line_offset ) const{
	int line = textCursor().block().firstLineNumber();
	if( line != 0 ) line -= line_offset;
	QStringList lines = toPlainText().split('\n');
	if( !lines.empty() || lines.size() > line )
	{
		QString lne = lines[line];
		return lne;
	}
	return "";
}
QString MaterialTextEdit::findIndentationLevel( int line_offset, int level_offset ) const
{
	int numSp = 0;
	int numTb = 0;
	QString line = currentLine(line_offset);
	for( int i=0; (i<line.size() && (line[i] == ' ' || line[i] == '\t')); i++ )
	{
		QChar c = line[i];
		if( c == '\t' ) numTb ++;
		if( c == ' ' ) numSp ++;
	}
	QString ind;
	for( int iS = 0; iS < numSp; iS++ ) ind += QString(' ');
	for( int iT = 0; iT < numTb+level_offset; iT++ ) ind += QString('\t');
	return ind;
}
void MaterialTextEdit::keyPressEvent( QKeyEvent *evt ){
	if( evt->key() == Qt::Key_Space && evt->modifiers().testFlag( Qt::ControlModifier ) )
	{
		QTextCursor tc( textCursor() );
		tc.select( QTextCursor::WordUnderCursor );
		mCompleter->popup( mapToGlobal(cursorRect().topRight()) );
	}
	else{
		static bool brace = false;
			static bool bracel = false;
			static bool bracer = false;
		if( evt->key() == Qt::Key_BraceLeft ){
			brace = bracel = true;
		}
		else if( evt->key() == Qt::Key_BraceRight ){
			brace = bracer = true;
		}
		switch( evt->key() )
		{
		case Qt::Key_BraceLeft:
			insertPlainText( "{" );
			break;
		case Qt::Key_BraceRight:
			insertPlainText( "}" );
			break;
		case Qt::Key_Return:
			if( brace ){
				if( bracel ) insertPlainText( "\r\n"+findIndentationLevel(0,1) );
				else if( bracer ) insertPlainText( "\r\n"+findIndentationLevel(0,0) );
			}
			else{
				if( currentLine( 0 ).right(1) == "{" ) insertPlainText( "\r\n"+findIndentationLevel(0,1) );
				else if( currentLine( 0 ).right(1) == "}" ) insertPlainText( "\r\n"+findIndentationLevel(0,0) );
				else insertPlainText( "\r\n"+findIndentationLevel(0,0) );
			}
			break;
		default:
			brace = bracel = bracer = false;
			QPlainTextEdit::keyPressEvent( evt );
		};
	}
}
void MaterialTextEdit::resizeEvent(QResizeEvent *e)
{
    QPlainTextEdit::resizeEvent(e);

    QRect cr = contentsRect();
    mLineArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}

void MaterialTextEdit::highlightCurrentLine()
{
    QList<QTextEdit::ExtraSelection> extraSelections;

    if (!isReadOnly()) {
        QTextEdit::ExtraSelection selection;

        QColor lineColor = QColor(Qt::yellow).lighter(180);

        selection.format.setBackground(lineColor);
        selection.format.setProperty(QTextFormat::FullWidthSelection, true);
        selection.cursor = textCursor();
        selection.cursor.clearSelection();
        extraSelections.append(selection);
    }

    setExtraSelections(extraSelections);
}

void MaterialTextEdit::lineNumberAreaPaintEvent(QPaintEvent *event)
 {
     QPainter painter(mLineArea);
     painter.fillRect(event->rect(), Qt::lightGray);

	 QTextBlock block = firstVisibleBlock();
     int blockNumber = block.blockNumber();
	 int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
     int bottom = top + (int) blockBoundingRect(block).height();

     while (block.isValid() && top <= event->rect().bottom()) {
         if (block.isVisible() && bottom >= event->rect().top()) {
             QString number = QString::number(blockNumber + 1);
             painter.setPen(Qt::black);
             painter.drawText(0, top, mLineArea->width(), fontMetrics().height(),
                              Qt::AlignRight, number);
         }

         block = block.next();
         top = bottom;
         bottom = top + (int) blockBoundingRect(block).height();
         ++blockNumber;
     }
 }
void MaterialTextEdit::setupEditor( )
{
	QFont font;
	font.setFamily("Courier");
	font.setFixedPitch(true);
	font.setPointSize(10);
	setFont(font);
	
	mCompleter = new MaterialCompleter(this);
	mHighlighter = new MaterialCodeHighlighter(document());
}